package com.its.myalgorithm.day01;

/**
 * @projectName: dgl-algorithm
 * @package: com.its.myalgorithm.day01
 * @className: Code01_PrintBinary
 * @author: DONG GL
 * @description: TODO
 * @date: 2022/3/29 15:53
 * @version: 1.0
 */
public class PrintBinary {
    /**
     * 补充知识
     *  & 与	两个位都为 1 时，结果才为 1
     *  ^ 异或 两个位相同为0，相异为1
     *  ~	取反	0变 1，1变 0
     *  <<	左移	各二进位全部左移若干位，高位丢弃，低位补0
     *  >>	右移	各二进位全部右移若干位，对无符号数，高位补 0，有符号数，各编译器处理方法不一样，有的补符号位（算术右移），有的补 0（逻辑右移）
     *  >>>	无符号右移 无符号右移，忽略符号位，空位都以 0 补齐
     *
     *  TODO &
     *      运算规则 0&0=0  0&1=0  1&0=0  1&1=1 两位同时为 1，结果才为 1，否则结果为 0。
     *
     *  TODO | 或运算
     *       运算规则 0|0=0  0|1=1  1|0=1  1&1=1 只要有 1，结果为 1， 否则结果为 0。
     *
     *  TODO ^运算规则
     *      0^0=0  0^1=1  1^0=1  1^1=0 参加运算的两个对象，如果两个相应位相同为 0，相异为 1。
     *      异或运算性质:
     *      交换律
     *      结合律：(a^b)^c == a^(b^c)
     *      对于任何数 x，都有 x^x=0，x^0=x
     *      自反性：a^b^b=a^0=a
     *
     *  TODO ~运算规则
     *      参加运算的一个数据，按二进制进行“取反”运算。
     *      对一个二进制数按位取反，即将 0 变 1，1 变 0。
     *
     *  TODO 左移运算符（<<）
     *  定义：将一个运算对象的各二进制位全部左移若干位（左边的二进制位丢弃，右边补 0）。
     *  例如：设 a=1010 1110，a = a<< 2 将 a 的二进制位左移 2 位、右补 0，即得 a=1011 1000。
     *  说明：若左移时舍弃的高位不包含 1，则每左移一位，相当于该数乘以 2。
     *
     *  TODO 右移运算符（>>）
     *      定义：将一个数的各二进制位全部右移若干位，正数左补 0，负数左补 1，右边丢弃。
     *      例如：a=a>>2 将 a 的二进制位右移 2 位，左补 0 或者 左补 1 得看被移数是正还是负。
     *      说明：操作数每右移一位，相当于该数除以 2。
     *      用符号位来补
     *
     *  TODO 无符号右移（>>>）
     *      在计算机中负数采用二进制的补码表示，即 10 进制转为 2 进制得到的是原码，将原码按位取反得到的是反码，反码加 1 得到补码。
     *      二进制的最高位是符号位，0 表示正，1 表示负。
     *      >>> 与 >> 唯一的不同是它无论原来的最左边是什么数，统统都用 0 填充。
     *      复合赋值运算符
     *
     * 位运算符与赋值运算符结合，组成新的复合赋值运算符，它们是：
     * &= 例：a&=b 相当于 a=a&b
     * |= 例：a|=b 相当于 a=a|b
     * >>= 例：a>>=b 相当于 a=a>>b
     * <<= 例：a<<=b 相当于 a=a<<b
     * ^= 例：a^=b 相当于 a=a^b
     *
     *
     * TODO 实现打印一个整数的二进制
     */
    public static void printInt(int num) {
        //打印1
        // 循环32 次
        for (int i = 31; i >= 0; i--) {
            /**
             * 第一次循环 ：num 00000000000000000000000000000001
             * i=31
             * 1<<31  10000000000000000000000000000000
             * num & 1 << i
             *  00000000000000000000000000000001
             *  &
             *  10000000000000000000000000000000
             *  --------------------------------
             *  00000000000000000000000000000000
             *  (num & (1 << i)) 结果为0  输出0
             *
             *  第二次循环
             *  i=30
             *  i<<30 01000000000000000000000000000000
             *  num & 1 << 30
             *  00000000000000000000000000000001
             *  &
             *  01000000000000000000000000000000
             *  --------------------------------
             *  00000000000000000000000000000000
             *  (num & (1 << i)) 结果为0  输出0
             *
             *  i=1
             *  i<<1 00000000000000000000000000000010
             *  num & 1 << 1
             *  00000000000000000000000000000001
             *  &
             *  00000000000000000000000000000010
             *  --------------------------------
             *  00000000000000000000000000000000
             *  (num & (1 << i)) 结果为0  输出0
             *
             *  1=0
             *  i<<1 00000000000000000000000000000001
             *  num & (1<<0)
             *  00000000000000000000000000000001
             *  &
             *  00000000000000000000000000000001
             *  --------------------------------
             *  00000000000000000000000000000001
             *  (num & (1 << i)) 结果为1  输出1             *
             *
             */
            //
            //
            System.out.print((num & (1 << i)) == 0 ? "0" : "1");
        }
        System.out.println();

    }

    /**
     *  TODO 实现打印一个lang的二进制
     * @param num
     */
    public static void printLang(Long num) {
        for (int i = 63; i >= 0; i--) {
            System.out.print((num & (1 << i)) == 0 ? "0" : "1");
        }
        System.out.println();
    }


    public static void main(String[] args) {
        // 32 位 任何数的左移1位 都等于num*2
        int num =1;
        System.out.println("1=============================");
        printInt(num);

        int a = 123183213;
        int b = 324324324;
        System.out.println("a=============================");
        printInt(a);
        System.out.println("b=============================");
        printInt(b);
        System.out.println("a & b=============================");
        printInt(a & b);
        System.out.println();
        System.out.println("a | b=============================");
        printInt(a | b);
        System.out.println("a ^ b=============================");
        printInt(a ^ b);
        System.out.println("=============================");


        printLang(8L);
        System.out.println("0000000000000000000000000000000100000000000000000000000000000001".length());

        printInt(1<<31);

        //有符号 + - -2的31到2的31次方-1
        System.out.println("int类型的最大值=============================");
        //int类型的最大值 第31位的 为0 其他为1
        printInt(Integer.MAX_VALUE);

        System.out.println("-1二进制=============================");
        //高位是1 表示负数
        //其他为全是1   取反 +1 表示 负几
        //11111~111  取反 +1 0000~00001
        printInt(-1);
        System.out.println("~-1二进制=============================");
        printInt(~-1);


        System.out.println("int类型的最小值=============================");
        //10000000000000000000000000000000 -2的31次方
        printInt(Integer.MIN_VALUE);
        System.out.println("~int类型的最小值=============================");
        printInt(~Integer.MIN_VALUE);
        //高位为1 为负数 取反
        System.out.println("~int类型的最小值+1=============================");
        printInt(~Integer.MIN_VALUE+1);



        //一个数的相反数  就等于这个数本身取反+1
        int c =3;
        int d = -3;
        int d1 =(~c+1);
        System.out.println(c);
        System.out.println(d);
        System.out.println(d1);

    }
}
